﻿using System;
using System.Net;
using System.Text;

namespace Storage.Core
{
	internal class FastBinaryDeserializer : IBinaryDeserializer
	{
		public FastBinaryDeserializer(byte[] buffer, int offset)
		{
			this.buffer = buffer;
			this.offset = offset;
		}

		public short ReadInt16()
		{
			var result = BitConverter.ToInt16(buffer, offset);
			offset += sizeof(Int16);
			return result;
		}

		public ushort ReadUInt16()
		{
			var result = BitConverter.ToUInt16(buffer, offset);
			offset += sizeof(UInt16);
			return result;
		}

		public Int32 ReadInt32()
		{
			var result = BitConverter.ToInt32(buffer, offset);
			offset += sizeof (Int32);
			return result;
		}

		public UInt32 ReadUInt32()
		{
			var result = BitConverter.ToUInt32(buffer, offset);
			offset += sizeof(UInt32);
			return result;
		}

		public Int64 ReadInt64()
		{
			var result = BitConverter.ToInt64(buffer, offset);
			offset += sizeof(Int64);
			return result;
		}

		public UInt64 ReadUInt64()
		{
			var result = BitConverter.ToUInt64(buffer, offset);
			offset += sizeof(UInt64);
			return result;
		}

		public float ReadFloat()
		{
			var bytes = new byte[sizeof (float)];
			Buffer.BlockCopy(buffer, offset, bytes, 0, bytes.Length);
			offset += bytes.Length;
			return BitConverter.ToSingle(bytes, 0);
		}

		public double ReadDouble()
		{
			var result = BitConverter.ToDouble(buffer, offset);
			offset += sizeof(double);
			return result;
		}

		public bool ReadBool()
		{
			return ReadInt32() != 0;
		}

		public byte ReadByte()
		{
			var result = buffer[offset];
			offset++;
			return result;
		}

		public byte[] ReadByteArray()
		{
			Int32 size = ReadInt32();
			var result = new byte[size];
			Buffer.BlockCopy(buffer, offset, result, 0, size);
			offset += size;
			return result;
		}

		public string ReadString()
		{
			return ReadString(Encoding.UTF8);
		}

		public string ReadString(Encoding encoding)
		{
			Int32 size = ReadInt32();
			var result = encoding.GetString(buffer, offset, size);
			offset += size;
			return result;
		}

		public Guid ReadGuid()
		{
			var guidBytes = new byte[16];
			Buffer.BlockCopy(buffer, offset, guidBytes, 0, guidBytes.Length);
			offset += guidBytes.Length;
			return new Guid(guidBytes);
		}

		public IPAddress ReadIPAddress()
		{
			return new IPAddress(ReadByteArray());
		}

		public IPEndPoint ReadIPEndPoint()
		{
			return new IPEndPoint(ReadIPAddress(), ReadInt32());
		}

		public TimeSpan ReadTimeSpan()
		{
			return new TimeSpan(ReadInt64());
		}

		public DateTime ReadDateTime()
		{
			return DateTime.FromBinary(ReadInt64());
		}

		public byte[] ByteArray { get { return buffer; } }

		public int Position
		{
			get { return offset; }
			set { offset = value; }
		}

		private readonly byte[] buffer;
		private int offset;
	}
}
